package ru.jetsoft.reg112.desktop.data;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ru.jetsoft.reg112.desktop.BaseException;
import ru.jetsoft.reg112.desktop.DataFormatException;
import ru.jetsoft.reg112.desktop.InitException;

public class DicCache {

    private static final Map<Integer, Dictionary> dics = new HashMap<>();
    private static final String tagDictionary = "dictionary";
    private static final String tagItem = "item";
    private static final String attrCode = "code";
    private static final String attrName = "name";
    private static final String attrId = "id";
    private static final String attrTitle = "title";

    private DicCache() {
    }

    public static void load(String dirname) throws InitException {
        try {
            final File dicsDir = new File(dirname);
            for(final File dicFile : dicsDir.listFiles()) {
                if(!dicFile.isDirectory()) {
                    loadDic(dicFile.getPath());
                }
            }
        } catch(Exception ex) {
            throw new InitException("Failed to load dictionaries from directory " + dirname);
        }
    }

    private static void loadDic(String filename) throws InitException {
        try {
            validateDic(filename);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(filename);

            NodeList dicNodes = doc.getElementsByTagName(tagDictionary);
            if(dicNodes.getLength() != 1) {
                throw new BaseException("Not found expected single dictionary. Found " + dicNodes.getLength() + ".");
            }
            Node dicNode = dicNodes.item(0);

            Node codeNode = dicNode.getAttributes().getNamedItem(attrCode);
            if(codeNode == null) {
                throw new InitException("Not found expected dictionary code attribute.");
            }
            int code = Integer.valueOf(codeNode.getNodeValue());
            Node nameNode = dicNode.getAttributes().getNamedItem(attrName);
            if(nameNode == null) {
                throw new InitException("Not found expected dictionary name attribute.");
            }
            String name = nameNode.getNodeValue();

            Dictionary dic = new Dictionary(code, name);

            NodeList items = dicNode.getChildNodes();
            Node item;
            Node idNode;
            Node titleNode;
            for(int i = 0; i < items.getLength(); i++) {
                item = items.item(i);
                if(tagItem.equals(item.getNodeName())) {
                    idNode = item.getAttributes().getNamedItem(attrId);
                    if(idNode == null) {
                        throw new InitException("Not found expected dictionary item id attribute.");
                    }
                    titleNode = item.getAttributes().getNamedItem(attrTitle);
                    if(titleNode == null) {
                        throw new InitException("Not found expected dictionary item id attribute.");
                    }
                    dic.addItem(Integer.valueOf(idNode.getNodeValue()), titleNode.getNodeValue());
                }
            }

            dics.put(code, dic);
        } catch(Exception ex) {
            throw new InitException("Failed to load dictionary from file " + filename, ex);
        }
    }

    private static void validateDic(String filename) throws BaseException {
        //todo: validate dic using xsd
    }

    public static Collection<String> getDicValues(int code) throws DataFormatException {
        Dictionary dic = dics.get(code);
        if(dic == null) {
            throw new DataFormatException("Unknown dictionary code " + code);
        }
        return dic.getItemTitles();
    }

    public static String getDicValue(int code, int id) throws DataFormatException {
        Dictionary dic = dics.get(code);
        if(dic == null) {
            throw new DataFormatException("Unknown dictionary code " + code);
        }
        return dic.getItemTitle(id);
    }

    public static Integer getDicId(int code, String value) throws DataFormatException {
        Dictionary dic = dics.get(code);
        if(dic == null) {
            throw new DataFormatException("Unknown dictionary code " + code);
        }
        for(Map.Entry<Integer, String> entry: dic.getItems().entrySet()) {
            if(entry.getValue().equals(value)) {
                return entry.getKey();
            }
        }
        throw new DataFormatException("Unknown value '" + value + "' of dictionary with code " + code);
    }
}
